home *** CD-ROM | disk | FTP | other *** search
/ PD ROM 1 / PD ROM Volume I - Macintosh Software from BMUG (1988).iso / Programming / Programming Tools / Turbo Pascal / Utilities / COMPAT.PAS next >
Encoding:
Pascal/Delphi Source File  |  1987-06-16  |  16.5 KB  |  580 lines  |  [TEXT/ttxt]

  1. unit Compat(56);
  2. { Implements several "Turbo" routines that are not built into
  3.   Turbo for the Mac.
  4.    
  5.   Last Edit: 3/25/87
  6.   version 1.00
  7.   written by : Joe Schrader 76703,4161
  8. }
  9. {=================================================================}
  10. interface
  11. uses MemTypes, QuickDraw, OSIntF, ToolIntF;
  12.  
  13. const
  14.   MacBlockSize = 512;          { Standard block size on Macintosh }
  15.   TurboBlockSize = 128;
  16.               { Set to 128 for compatibility with  implementations of }
  17.                                    { Turbo Pascal  on other machines. }
  18. type 
  19.   PackedByte = packed record 
  20.                       { this is the easiest way to force a variable }
  21.                       { to occupy 1 byte }
  22.                         b : byte;
  23.                       end;
  24.   UntypedFile = file of PackedByte;  { Block operations are on untyped, }
  25.                                                    { that is, any files }
  26.  
  27. { File routines }
  28.  
  29. procedure Append(var f : text; 
  30.                  FN : str255);
  31. { Opens a text file named by FN, for appending.  That is, this
  32.   routine opens the file and seeks to the end so you can add
  33.   text with Write(f, ...) }                 
  34.                                              
  35. procedure BlockRead(var F : UntypedFile;
  36.                     var Buf;
  37.                         NumBlocks : LongInt;
  38.                     var BlocksRead : LongInt);
  39. { Reads NumBlocks blocks of data from F into Buf.  BlocksRead
  40.   specifies the number of blocks actually read. }
  41.  
  42.                     
  43. procedure BlockWrite(var F : UntypedFile;
  44.                     var Buf;
  45.                         NumBlocks : LongInt;
  46.                     var BlocksWritten : LongInt);
  47. { Writes Numblocks of data from Buf to the file referred to by
  48.   F.  BlocksWritten specifies the actual number of bytes written }
  49.  
  50. procedure SetBlockSize(var F : UnTypedFile;
  51.                        Size : LongInt);
  52. { Sets the block size used for all subsequent block operations
  53.   and Seek's used on F. }
  54.   
  55. procedure EraseF(FileName : String);
  56. { Since the identifier Erase used in QuickDraw supercedes Turbo's rename,
  57.   you can use this procedure which is simpler than the OS equivalent }
  58.   
  59.                  
  60. procedure Execute(ProgName : Str255);
  61. { Executes, launches the program specified by ProgName.  If
  62.   the program is not found this routine will crash, so the
  63.   programmer should check to see if it us, before-hand.
  64.   WARNING: Don't call this routine while running inside of the
  65.   Turbo environment i.e. only use it with a program you run 
  66.   from disk
  67. }  
  68.   
  69. function LongFilePos(var F) : real;
  70.  
  71. function LongFileSize(var F) : real;
  72.  
  73. procedure LongSeek(var F; SeekPos : real);
  74.  
  75. procedure RenameF(OldFileNm, NewFileNm : String);
  76. { Since the Rename procedure in OSIntF supercedes Turbo's rename,
  77.   you can use this procedure which is simpler than the OS equivalent }
  78.   
  79. function ParamCount : integer;
  80.  
  81. function ParamStr(Param : integer) : string;
  82.  
  83. { Random number routines }
  84.  
  85. procedure Randomize;
  86. { Sets the seed for the random number generator using the system
  87.   clock. If you want to seed the generator yourself, just set 
  88.   the global variable, Seed directly. }
  89.     
  90. function Random(Max : LongInt) : LongInt;
  91. { Returns a "random" Long integer in the range 0..Max }
  92.  
  93. function RandomR : real;
  94. { Returns a "random" real number between 0 and 1.  On other 
  95.   implementations of Turbo this built-in function is called Random 
  96.   like the routine above it.  This cannot be duplicated at the
  97.   Pascal level, however. }
  98.   
  99. { General routines }
  100.   
  101. procedure ClrEol;
  102. { Clears to the end of the current line.  Simple call-through to routine 
  103.   with Lisa Pascal compatible name } 
  104.    
  105. procedure ClrScr;
  106. { Clears the screen.  Simple call-through to routine with Lisa Pascal 
  107.   compatible name }  
  108.   
  109. procedure Delay(DelayTime : LongInt);
  110. { Delays DelayTime # of milliseconds }
  111.  
  112. function Frac(Num : real) : real;
  113. { Returns the fractional part of Num }
  114.  
  115. procedure FreeMem(var P : Ptr;
  116.                   NumBytes : integer);
  117. { Reclaims the space allocated to P }
  118.  
  119. procedure GetMem(var P : Ptr;
  120.                  NumBytes : integer);
  121. { Allocates Numbytes bytes and set P as a pointer to this block }
  122.  
  123. procedure NoSound;
  124. { Turns off the speaker(s) }  
  125.  
  126. procedure Sound(Freq : LongInt);
  127. { Makes a tone of Freq frequency }
  128.  
  129. function UpCase(ch : char): char; 
  130. { Returns the upper case equivalent of ch } 
  131. inline 
  132.    $301F, { UpCase MOVE.W (SP)+,D0 ; GetCh }
  133.    $0C40,
  134.    $0061, { CMP.W #'a',D0 ; skip if not lower case }
  135.    $6D0A, { BLT.S @1 }
  136.    $0C40,
  137.    $007A, { CMP.W #'z',D0 }
  138.    $6E04, { BGT.S @1 }
  139.    $0440, 
  140.    $0020, { SUB.W #$20,D0 }
  141.    $3E80; { @1 MOVE.W D0,(SP) }
  142.  
  143. function WhereX : integer;
  144. { Returns the current X coordinate in PasConsole. Note: this only
  145.   works with the default font. }
  146.   
  147. function WhereY : integer;
  148. { Returns the current Y coordinate in PasConsole. Note: this only
  149.   works with the default font. }
  150.  
  151. var 
  152.   CON,        { File variable associated with console device driver }
  153.   LST,        { "                          "  the printer }
  154.   KBD : text; { "                          " the keyboard device }
  155.   Seed : LongInt; { Seed for the random number generator }
  156. {=================================================================}  
  157. implementation
  158. var
  159.   FileErr : OSErr;
  160.  
  161. { The following type declarations represent the internal format of
  162.   a Turbo file variable (covered on page 330 of the Turbo for the Mac 
  163.   Reference Manual).  For the file manager calls we need the file 
  164.   reference number.  To access the fields in a file variable we map 
  165.   the record structure using value casting, for eg. FileRec(F),
  166.    which is covered on page 244.}  
  167. type
  168.   FileBuf = packed array[0..MaxInt] of char;
  169.   FileBufferPtr = ^FileBuf;
  170.   ProcPtr = ^Integer;
  171.   FileRec = record    { Internal format of a Turbo file variable }
  172.               FInpFlag : boolean;
  173.               FOutFlag : boolean;
  174.               FRefNum : integer;  { Reference number is used for }
  175.               FVRefNum : integer;       { Mac File Manager calls }
  176.               FBufSize : integer;
  177.               FBufPos : integer;
  178.               FBufEnd : integer;
  179.               FBuffer : FileBufferPtr;
  180.               FInOutProc : ProcPtr;
  181.             end;
  182.  
  183. function Exists(FN : String) : boolean;
  184. var
  185.   F : UntypedFile;
  186.   Ok : boolean;
  187. begin
  188. {$I-}
  189.  Reset(F, FN);
  190.  Ok := (IOResult = 0);
  191.  {$I+}
  192.  if Ok then
  193.    Close(F);
  194.  Exists := Ok;
  195. end; { Exists }
  196.  
  197. procedure Append{var f : text; 
  198.                  FN : str255};
  199. { Opens a text file named by FN, for appending.  That is, this
  200.   routine opens the file and seeks to the end so you can add
  201.   text with Write(f, ...) }                  
  202. begin
  203.   if not Exists(FN) then
  204.   begin
  205.     Rewrite(F, FN);
  206.     Exit;
  207.   end;
  208.   Reset(f, Fn);
  209.   with FileRec(f) do
  210.   begin
  211.     FInpFlag := false;
  212.     FOutFlag := true;
  213.     FileErr := SetFPos(FRefNum, FsFromLEOF, 1);
  214.     if (FileErr <> NoErr) and (FileErr <> EofErr)  then
  215.       SysError(-FileErr);
  216.   end;
  217. end; { Append }                 
  218.  
  219. procedure BlockRead{var F : UntypedFile;
  220.                     var Buf;
  221.                         NumBlocks : LongInt
  222.                     var BlocksRead : LongInt};
  223. { Reads NumBlocks blocks of data from F into Buf.  BlocksRead
  224.   specifies the number of blocks actually read. }
  225.                     
  226. begin
  227.   with FileRec(F) do { Type cast file variable so we can access fields }
  228.   begin
  229.     BlocksRead := NumBlocks * FBufSize;  { Get the # of bytes to read }
  230.     if BlocksRead > 0 then
  231.     begin
  232.       FileErr := FSRead(FRefNum, BlocksRead, @Buf);
  233.       if (FileErr <> NoErr) and (FileErr <> EofErr) then
  234.         SysError(-FileErr);
  235.       BlocksRead := BlocksRead div FBufSize; { Convert to # of blocks }
  236.     end;
  237.   end;
  238. end; { BlockRead }
  239.                     
  240. procedure BlockWrite{var F : UntypedFile;
  241.                      var Buf;
  242.                         NumBlocks : LongInt;
  243.                      var BlocksWritten : LongInt};
  244. { Writes Numblocks of data from Buf to the file referred to by
  245.   F.  BlocksWritten specifies the actual number of bytes written }                                         
  246. begin
  247.   with FileRec(F) do   { Type cast file variable so we can access fields }
  248.   begin
  249.     BlocksWritten := NumBlocks * FBufSize; { Get the # of bytes to read }
  250.     if BlocksWritten > 0 then
  251.     begin
  252.       FileErr := FSWrite(FRefNum, BlocksWritten, @Buf);    { OSIntf call }
  253.       if (FileErr <> NoErr) then
  254.         SysError(-FileErr);
  255.       BlocksWritten := BlocksWritten div FBufSize;
  256.                                                 { Convert to # of blocks }
  257.     end;
  258.   end;
  259. end; { BlockWrite }
  260.  
  261. procedure SetBlockSize{var F : UnTypedFile;
  262.                        Size : LongInt};
  263. { Sets the block size used for all subsequent block operations
  264.   (until another SetBlockSize is used), note: this procedure need
  265.   not be called }
  266. begin
  267.   with FileRec(F) do
  268.   FBufSize := Size;
  269. end; { SetBlockSize }
  270.  
  271. procedure EraseF{FileName : String};
  272. { Since the identifier Erase used in QuickDraw supercedes Turbo's rename,
  273.   you can use this procedure which is simpler than the OS equivalent }
  274. begin
  275.   FileErr := FSDelete(FileName, 0); 
  276.   if (FileErr <> NoErr) and (FileErr <> FnFErr) then  
  277.   { If error this will generates a bomb box }
  278.     SysError(-FileErr); { Resume and Turbo will find error, if in memory }   
  279. end; { EraseF }
  280.  
  281. procedure Execute{ProgName : Str255};
  282. { Executes, launches the program specified by ProgName.  If
  283.   the program is not found this routine will crash, so the
  284.   programmer should check to see if it exists, before-hand.
  285.   WARNING: Don't call this routine while running inside of the
  286.   Turbo environment i.e. only use it with a program you run 
  287.   from disk
  288. }
  289. type 
  290.   LaunchRec = record
  291.                 ProgramName : ^Str255; { pointer to the program name }
  292.                 SoundBuffer : integer; { indicates which buffers to use }
  293.               end;
  294.   { The variables in this record make it easy for the inline
  295.     routine below to call the launch trap } 
  296.               
  297. procedure LaunchIt(var LaunchVar : LaunchRec);
  298. { The Launch routine can only be called from assembler.
  299.   So below is the strip of inline code that accomplishes
  300.   that. For more information see Inside Macintosh II 59-60.
  301.   On entry (to launch trap macro):
  302.     (A0): points to applications file name
  303.     4(A0):configuration of sound and screen buffer 
  304. }
  305. inline 
  306.   $205F,   { MOVE.L  (SP)+,A0 } { move paramater into A0 }
  307.   $A9F2;            { _Launch }
  308. var
  309.   LaunchVar : LaunchRec;
  310.   F : file of byte; 
  311.   Name : Str255;
  312.     
  313. begin
  314.   Reset(F, ProgName);  { This is called so the program will crash here }
  315.                         { if the file is not there, rather than on the }
  316.                            { launch, which gives unpredictable results }     
  317.   Close(F);
  318.   Name := ProgName;
  319.   with LaunchVar do
  320.   begin
  321.     SoundBuffer := 0;
  322.     { uses Main sound and screen buffers.  If you want the current
  323.       buffer, you need to write inline to get it from the variable
  324.       CurPageOption.  I have not done this yet. }
  325.     ProgramName := @Name;
  326.   end;
  327.   LaunchIt(LaunchVar);
  328. end; { Execute }
  329.  
  330.  
  331. function LongFilePos{(var F) : real};
  332. var
  333.   FileErr : OSErr;
  334.   FPos : LongInt;
  335. begin
  336.   with FileRec(F) do
  337.   begin
  338.     FileErr := GetFPos(FRefNum, FPos);
  339.     if (FileErr <> NoErr) then
  340.       SysError(-FileErr);
  341.     LongFilePos := FPos div FBufSize;
  342.   end;
  343. end; { LongFilePos }
  344.  
  345. function LongFileSize{(var F) : real};
  346. var
  347.   FileErr : OSErr;
  348.   FSize : LongInt;
  349. begin
  350.   with FileRec(F) do
  351.   begin
  352.     FileErr := GetEOF(FRefNum, FSize);
  353.     if (FileErr <> NoErr) then
  354.       SysError(-FileErr);
  355.     LongFileSize := FSize div FBufSize;
  356.   end;
  357. end; { LongFileSize }
  358.  
  359. procedure LongSeek{(var F; SeekPos : real)};
  360. type
  361.   Long = LongInt;
  362. var
  363.   FileErr : OSErr;
  364.   FSize : LongInt;
  365. begin
  366.   with FileRec(F) do
  367.   begin
  368.     FileErr := SetFPos(FRefNum, FsFromStart, Long(SeekPos) * Long(FBufSize));
  369.     if (FileErr <> NoErr) then
  370.       SysError(-FileErr);
  371.   end;
  372. end; { LongSeek }
  373.  
  374. function ParamCount{ : integer};
  375. var
  376.   Message,
  377.   Count : integer;
  378.   
  379. begin
  380.   CountAppFiles(Message, Count);
  381.   ParamCount := Count;
  382. end; { ParamCount }
  383.  
  384. function ParamStr{(Param : integer) : string};
  385. var
  386.   AppFileInfo : AppFile;
  387.   
  388. begin
  389.   GetAppFiles(Param, AppFileInfo);
  390.   ParamStr := AppFileInfo.FName;
  391. end; { ParamStr }
  392.  
  393. procedure RenameF{OldFileNm, NewFileNm : String};
  394. { Since the Rename procedure in OSIntF supercedes Turbo's rename,
  395.   you can use this procedure which is simpler than the OS equivalent }
  396. begin
  397.   FileErr := Rename(OldFileNm, 0, NewFileNm);
  398.   if FileErr <> NoErr then  { If error this will generates a bomb box }
  399.     SysError(-FileErr); { Resume and Turbo will find error, if in memory }           
  400. end; { RenameF }
  401.  
  402. { Random number routines }
  403.   
  404. procedure Randomize;
  405. { Sets the seed for the random number generator using the system
  406.   clock. If you want to seed the generator yourself, just set 
  407.   the global variable, Seed directly. }
  408. begin
  409.   Seed := TickCount;
  410. end; { Randomize }
  411.   
  412. function Random{(Max : LongInt) : LongInt};
  413. { Returns a "random" Long integer in the range 0..Max }
  414. begin
  415.   Seed := (Seed * $81)+$361862E9; { next value for the seed }
  416.   Random := (Seed SHR 16) MOD Max;
  417. end;
  418.  
  419. function RandomR{ : real};
  420. { Returns a "random" real number between 0 and 1.  On other 
  421.   implementations of Turbo this function is called Random
  422.   like the routine above it.  This cannot be duplicated at 
  423.   the Pascal level, however. }
  424. var
  425.   r : real;
  426. begin
  427.   Seed := (Seed * $81)+$361862E9;
  428.   r := Seed;
  429.   RandomR := abs(r) / 2147483648.0;
  430. end; { RandomR }
  431.  
  432. { General routines }
  433.  
  434. procedure ClrEol;
  435. { Clears to the end of the current line.  Simple call through to routine 
  436.   with Lisa Pascal compatible name }
  437. begin
  438.   ClearEol;
  439. end; { ClrEol }
  440.  
  441. procedure ClrScr;
  442. { Clears the screen.  Simple call through to routine with 
  443.   Lisa Pascal compatible name }
  444. begin
  445.   ClearScreen; 
  446. end; { ClrScr }
  447.  
  448. procedure Delay{DelayTime : LongInt};
  449. { Delays DelayTime # of milliseconds }
  450.  
  451. procedure DelayIt(ticks: Longint); inline $205F,$A03B;
  452.  
  453. begin { Delay }
  454.   DelayTime := DelayTime div 17;
  455.   if DelayTime > 0 then
  456.     DelayIt(DelayTime);
  457. end; { Delay }
  458.  
  459. function Frac{(Num : real) : real};
  460. { Returns the fractional part of Num }
  461. begin
  462.   Frac := Num - Int(Num);
  463. end;
  464.  
  465. procedure FreeMem{var P : Ptr;
  466.                   NumBytes : integer};
  467. { Reclaims the space allocated to P }
  468. begin
  469.   Dispose(p);
  470. end; { FreeMem }
  471.  
  472. procedure GetMem{var P : Ptr;
  473.                  NumBytes : integer};
  474. { Allocates Numbytes bytes and set P as a pointer to this block }
  475. begin
  476.   P := NewPtr(Numbytes);
  477. end; { GetMem }
  478.  
  479. procedure NoSound;
  480. { Turns off the speaker(s) }
  481. begin
  482.   StopSound;
  483. end;
  484.  
  485. procedure Sound{Freq : LongInt};
  486. { Makes a tone of Freq frequency }
  487. const
  488.    FreqItem = 4;
  489.    BufSize  = 8;
  490.  
  491.  var
  492.    count    : integer;
  493.    mySwPtr  : SWSynthPtr;
  494.    myHandle : Handle;
  495.    myPtr    : Ptr;
  496.  
  497. begin   
  498.   count := 783360 div freq;
  499.   myHandle := newHandle(BufSize);
  500.   Hlock(myHandle);
  501.   myPtr := myHandle^;
  502.   mySwPtr := SWSynthPtr(myPtr);
  503.   with mySwPtr^ do
  504.   begin
  505.     mode := swmode; { use sine wave mode }
  506.     triplets[0].count := count;
  507.     triplets[0].amplitude := 127;
  508.     triplets[0].duration := 60;
  509.   end;
  510.   StartSound(myPtr, BufSize, pointer(-1));
  511.   HUnlock(myHandle);
  512.   DisposHandle(myHandle);
  513. end; { Sound }
  514.  
  515. function WhereX{ : integer};
  516. { Returns the current X coordinate in PasConsole. Note: this only
  517.   works with the default font. }
  518. begin
  519.   with thePort^ do
  520.     WhereX := PnLoc.h div 6;
  521. end;
  522.  
  523. function WhereY{ : integer};
  524. { Returns the current Y coordinate in PasConsole. Note: this only
  525.   works with the default font. }
  526. begin
  527.   with thePort^ do
  528.     WhereY := PnLoc.v div 9;
  529. end;
  530.   
  531.  
  532. function KBDIn(var F : FileRec) : integer;
  533. { Implements the KBD device driver for compatibility wit other 
  534.   implementations of Turbo Pascal. You can now do Read(KBC, ch).  
  535.   Note: this should only be used with CHARACTER variables.  If you 
  536.   move this device driver to another unit, also take InitKBD below. }
  537.   
  538. var
  539.   P : integer;
  540.   ch : char;
  541. begin
  542.   KBDIn := 0;
  543.   with F do
  544.     if FInpFlag then { We will be only outputting with this device }
  545.     begin    
  546.       ch := ReadChar;   { ReadChar is equivalent to Read(KBD, ) }
  547.       FBuffer^[0] := ch;
  548.       FBufEnd := 1;
  549.       FBufPos := 0;
  550.     end;
  551. end; { KBDIn }
  552.  
  553. procedure InitKBD;
  554. { Call only once at the beginning of the program to initialize
  555.   the KBD device driver. }
  556. begin
  557.   Device('KBD:', @KBDIn);
  558.   Reset(KBD,'KBD:');
  559.   with FileRec(KBD) do
  560.     FBufSize := 1;
  561. end; { InitKBD }
  562.     
  563. procedure InitDevices;
  564. begin
  565.   InitKBD;
  566.   Rewrite(CON, 'Console:');
  567.   {$I-} { prevents crash if Printer is not there }
  568.   Rewrite(LST, 'Printer:');  
  569.   {$I+}
  570. end; { InitDevices }
  571.  
  572. var
  573.   SavePort : GrafPtr;
  574. begin { Initialization code for the unit }
  575.   GetPort(SavePort);
  576.   InitGraf(@thePort);
  577.   SetPort(SavePort);
  578.   InitDevices; { Initialization routine for device drivers }
  579. end. { Compat }